package com.yunjinsuke.recharge.scheduled;

import com.yunjinsuke.recharge.entity.RechargeOrder;
import com.yunjinsuke.recharge.redis.RedisKeyUtil;
import com.yunjinsuke.recharge.redis.RedisLockCommon;
import com.yunjinsuke.recharge.redis.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.jpa.repository.Modifying;
import org.springframework.scheduling.annotation.Async;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.EntityManager;
import java.util.List;
import java.util.stream.Collectors;


/**
 * 定时任务
 * 相关类：AsyncConfig 多线程执行定时任务
 * 通过网址：http://cron.qqe2.com/获取定时任务表达式
 */
@Component
// 异步类
@Async
@Slf4j
@EnableScheduling
public class ScheduledService {

    private final RedisLockCommon redisLockCommon;

    private final EntityManager entityManager;

    private final RedisUtil redisUtil;

    public ScheduledService(RedisUtil redisUtil, EntityManager entityManager, RedisLockCommon redisLockCommon) {
        this.redisUtil = redisUtil;
        this.entityManager = entityManager;
        this.redisLockCommon = redisLockCommon;
    }

    /**
     * 插入数据
     * 每5秒
     */
    @Scheduled(cron = "0/10 * * * * ?")
    @Transactional
    @Modifying
    public void insertRechargeOrder() {
        long time = System.currentTimeMillis();
        String rechargeOrderListKey = null;
        // 锁
        String lockRechargeOrderListKey = null;
        try {
            for (int num = 0; num < RedisKeyUtil.RECHARGE_ORDER_LIST_SIZE; num++) {
                rechargeOrderListKey = RedisKeyUtil.rechargeOrderListKey(num);
                // 有没有key
                if (redisUtil.hasKey(rechargeOrderListKey)) {
                    // 能不能加锁
                    if (redisLockCommon.tryLock(RedisKeyUtil.lockRechargeOrderListKey(num))) {
                        lockRechargeOrderListKey = RedisKeyUtil.lockRechargeOrderListKey(num);
                        break;
                    } else {
                        log.info("已经有线程正在处理:" + rechargeOrderListKey);
                    }
                }
            }
            // 暂无新订单处理
            if (rechargeOrderListKey == null) {
                log.info("订单处理:暂无新订单处理");
                return;
            }

            long size = redisUtil.lGetListSize(rechargeOrderListKey);
            if (size > 0) {
                log.info(String.format("订单处理:正在处理-%s", rechargeOrderListKey));
                // 订单列表 一次插入10000条
                List<RechargeOrder> rechargeOrderList = redisUtil.lGet(rechargeOrderListKey, 0, 10000)
                        .stream()
                        .map(o -> (RechargeOrder) o)
                        .collect(Collectors.toList());

                StringBuilder batchInsertSqlSb = new StringBuilder("insert into recharge_order (id, create_time, update_time, amount, mch_id, mobile, recharge_state, server_port) values ");
                rechargeOrderList.forEach(rechargeOrder -> {
                    batchInsertSqlSb.append(String.format("('%s', current_timestamp, current_timestamp, %d,'%s', '%s', '%s', '%s'),", rechargeOrder.getId(), rechargeOrder.getAmount(), rechargeOrder.getMchId(), rechargeOrder.getMobile(), rechargeOrder.getRechargeState(), rechargeOrder.getServerPort()));
                });
                String batchInsertSql = batchInsertSqlSb.substring(0, batchInsertSqlSb.length() - 1);

                // 执行插入SQL
                entityManager.createNativeQuery(batchInsertSql).executeUpdate();

                // 删除已经插入的数据
                for (Object o : rechargeOrderList) {
                    redisUtil.lRemove(rechargeOrderListKey, 1, o);
                }
                log.info("处理时间" + lockRechargeOrderListKey + ":" + (System.currentTimeMillis() - time));
            } else {
                log.info("订单处理:暂无新订单处理");
            }
        } finally {
            // 释放锁
            if (lockRechargeOrderListKey != null) {
                log.info("释放锁:" + lockRechargeOrderListKey);
                redisLockCommon.unlock(lockRechargeOrderListKey);
            }
        }
    }

}
